package com.nku.mason.masonframework.core.tools;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.nku.mason.masonframework.aop.AspectProxy;
import com.nku.mason.masonframework.aop.Proxy;
import com.nku.mason.masonframework.aop.ProxyManager;
import com.nku.mason.masonframework.core.annotations.Aspect;
/**
 * AOP功能加载工具
 * @author Mason
 * @date 2017年3月21日
 */
public final class AopTool {
	
	private AopTool(){
		//私有构造器，防止外部实例化
	}
	
	private static final Logger LOGGER = LoggerFactory.getLogger(AopTool.class);
	
	/**
	 * 完成AOP相关功能的初始化
	 */
	static {
		try {
			Map<Class<?>, Set<Class<?>>> proxyMap = createProxyMap();
			Map<Class<?>, List<Proxy>> targetMap = createTargetMap(proxyMap);
			for(Map.Entry<Class<?>, List<Proxy>> targetEntry : targetMap.entrySet()){
				Class<?> targetClass = targetEntry.getKey();
				List<Proxy> proxyList = targetEntry.getValue();
				Object proxy = ProxyManager.createProxy(targetClass, proxyList);
				BeanTool.setBean(targetClass, proxy);	//这里将被代理类的代理对象都放入了IOC容器中
			}
		} catch (Exception e) {
			LOGGER.error("aop failure",e);
		}
	}
	
	/**
	 * 获取代理类(切面类)和目标类之间的映射关系，一个代理类可以对应一个或多个目标类
	 * @return 返回代理类(切面类)和目标类之间的映射关系，一个代理类可以对应一个或多个目标类
	 * @throws Exception
	 */
	private static Map<Class<?>, Set<Class<?>>> createProxyMap() throws Exception{
		Map<Class<?>, Set<Class<?>>> proxyMap = new HashMap<Class<?>, Set<Class<?>>>();
		
		Set<Class<?>> proxyClassSet = ClassTool.getClassSetBySuper(AspectProxy.class);
		for(Class<?> proxyClass : proxyClassSet){
			if (proxyClass.isAnnotationPresent(Aspect.class)) {
				Aspect aspect = proxyClass.getAnnotation(Aspect.class);
				Set<Class<?>> targetClassSet = createTargetClassSet(aspect);
				proxyMap.put(proxyClass, targetClassSet);
			}
		}
		
		return proxyMap;
	}
	
	
	/**
	 * 获取带有Aspect注解的被代理的目标类的集合
	 * @param aspect
	 * @return 返回带有Aspect注解的被代理的目标类的集合
	 * @throws Exception
	 */
	private static Set<Class<?>> createTargetClassSet(Aspect aspect) throws Exception{
		Set<Class<?>> targetClassSet = new HashSet<Class<?>>();
		Class<? extends Annotation> annotation = aspect.value();
		if (annotation != null && !annotation.equals(Aspect.class)) {
			targetClassSet.addAll(ClassTool.getClassSetByAnnotation(annotation));
		}
		
		return targetClassSet;
	}
	
	/**
	 * 获取目标类和代理链之间的映射关系
	 * @param proxyMap 代理类(切面类)和目标类之间的映射关系，一个代理类可以对应一个或多个目标类
	 * @return 返回目标类和代理链之间的映射关系
	 */
	private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, Set<Class<?>>> proxyMap) throws Exception{
		Map<Class<?>, List<Proxy>> targetMap = new HashMap<Class<?>, List<Proxy>>();
		for(Map.Entry<Class<?>, Set<Class<?>>> proxyEntry : proxyMap.entrySet()){
			Class<?> proxyClass = proxyEntry.getKey();
			Set<Class<?>> targetClassSet = proxyEntry.getValue();
			for(Class<?> targetClass : targetClassSet){
				Proxy proxy = (Proxy) proxyClass.newInstance();
				if (targetMap.containsKey(targetClass)) {
					targetMap.get(targetClass).add(proxy);
				} else {
					List<Proxy> proxyList = new ArrayList<Proxy>();
					proxyList.add(proxy);
					targetMap.put(targetClass, proxyList);
				}
			}
		}
		return targetMap;
	}
}





































